﻿// Copyright (c) ZhangPeihang. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using BootstrapBlazor.Components;
using LaserMark.Extensions;
using LaserMark.Models;
using LaserMark.Components.Services;
using LaserMark.Components.Utils;
using LaserMark.Control.Service;
using LaserMark.DataAccess.Service;
using LaserMark.ModbusTCP;
using LaserMark.ModbusTCP.Abstraction;
using LaserMark.Print;
using LaserMark.SuperDog;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Options;
using LaserMark.View.Services;
using System.Text;
using System.Timers;
using System.Windows.Documents;
using static LaserMark.Control.Service.mc;

namespace LaserMark.Components.Pages
{
    public partial class Home : EventViewBaseComponent, IDisposable
    {
        private OriginalInfo Info { get; set; } = new();

        private int CurrentOriginalIndex { get; set; } = 0;

        private int CurrentPieceIndex { get; set; } = 0;

        private Original CurrentOriginal { get; set; } = new();

        [NotNull]
        private Table<Template>? Table { get; set; }

        private bool Continuous { get; set; } = false;

        private int Count { get; set; }

        [NotNull]
        private List<Template>? Items { get; set; } = new List<Template>();

        [NotNull]
        [Inject]
        private ToastService? ToastService { get; set; }

        [NotNull]
        [Inject]
        private SwalService? SwalService { get; set; }

        [NotNull]
        [Inject]
        private IGlobalStatus? GlobalStatus { get; set; }

        [Inject]
        [NotNull]
        private IMasterClientFactory? MasterClientFactory { get; set; }

        [Inject]
        [NotNull]
        private IDogService? DogService { get; set; }

        [NotNull]
        private ModBusMaster? Master { get; set; }

        [NotNull]
        [Inject]
        private ICodeTemplateService? CodeTemplateService { get; set; }

        [NotNull]
        [Inject]
        private IConnectLineService? ConnectLineService { get; set; }

        [NotNull]
        [Inject]
        private IOptions<MarkOption>? Options { get; set; }

        [NotNull]
        private MarkOption? MarkOption { get; set; }

        [NotNull]
        private SvgEditor? SvgEditor { get; set; }

        private string? Content { get; set; }

        [NotNull]
        private AutoResetEvent? MarkRestEvent { get; set; } = new(true);

        [NotNull]
        private ManualResetEvent? PauseRestEvent { get; set; } = new(true);

        [NotNull]
        private AutoResetEvent? Fifo1MarkRestEvent { get; set; } = new(true);

        private int PauseSegment { get; set; }

        private CancellationTokenSource PauseSource { get; set; } = new();

        [NotNull]
        private CancellationTokenSource? FinishToken { get; set; } = new();

        [NotNull]
        private System.Timers.Timer? AutoTaskTimer { get; set; }

        private bool IsAutoTask { get; set; }

        [NotNull]
        private System.Timers.Timer? Timer { get; set; }

        private bool IsAutoReadTask { get; set; }

        private bool IsEmergencyStop { get; set; }

        private bool FirstMark { get; set; }

        private string? ClassString(Original original) => CssBuilder.Default("footer-item ms-2")
            .AddClass("bg-primary", original.Equals(CurrentOriginal))
            .Build();

        protected override void OnInitialized()
        {
            base.OnInitialized();
            CommandNames.Add(RibbonTabConstants.ZeroBack);
            CommandNames.Add(RibbonTabConstants.AutoOrManual);
            CommandNames.Add(RibbonTabConstants.OpenFile);
            CommandNames.Add(RibbonTabConstants.SystemSettings);
            CommandNames.Add(RibbonTabConstants.SelectTemplate);
            CommandNames.Add(RibbonTabConstants.TaskList);
            CommandNames.Add(RibbonTabConstants.NewTemplate);
            CommandNames.Add(RibbonTabConstants.UpdaeteTemplate);
            CommandNames.Add(RibbonTabConstants.AuditLog);
            CommandNames.Add(RibbonTabConstants.Ezd3);
            CommandNames.Add(RibbonTabConstants.Run);
            CommandNames.Add(RibbonTabConstants.Stop);
            CommandNames.Add(RibbonTabConstants.ClearSts);
            CommandNames.Add(RibbonTabConstants.Pause);
            CommandNames.Add(RibbonTabConstants.OnKeep);
            MarkOption = Options.Value;
            if (Info.Originals.Count == 0)
            {
                GlobalStatus.ProductMessage = "当前未加载订单信息";
            }
        }

        protected override async Task OnInitializedAsync()
        {
            await base.OnInitializedAsync();

            Master = MasterClientFactory.Create();
            await Master.ConnectAsync();

            Timer = new System.Timers.Timer(500);
            Timer.Elapsed += Timer_Elapsed;
            Timer.Start();

            await Task.Delay(1000);
            var ret = await SwalService.ShowModal(new SwalOption()
            {
                Category = SwalCategory.Information,
                Content = "请先进行机械回零",
                ShowClose = false
            });
        }

        private async void Timer_Elapsed(object? sender, ElapsedEventArgs e)
        {
            if (GlobalStatus.IsRunning)
            {
                try
                {
                    if (GlobalStatus.IsEmergencyStop)
                    {
                        IsEmergencyStop = true;
                    }
                    else
                    {
                        IsEmergencyStop = false;

                        // 暂停
                        int value;
                        await Control.GetDi(0, mc.MC_GPI, out value);
                        var status = Convert.ToString(value, 2).PadLeft(16, '0');
                        if (status[14] == '0')
                        {
                            await Control.GetDi(0, mc.MC_GPI, out value);
                            var aa = Convert.ToString(value, 2).PadLeft(16, '0');
                            if (aa[12] == '1')
                            {
                                await ToastService.Warning("提示", "当前为手动模式");
                            }
                            else
                            {
                                await Control.SetDoBit(0, mc.MC_GPO, 3, 0);
                                await Control.SetDoBit(0, mc.MC_GPO, 4, 1);
                                await Control.Stop(0, 1 << 8, 0);
                                PauseSource.Cancel();
                                PauseRestEvent.Reset();
                                GlobalStatus.IsPause = true;
                                mc.GT_CrdStatus(0, 1, out _, out int segment, 0);
                                PauseSegment = segment;
                            }
                        }

                        // 运行
                        int value1;
                        await Control.GetDi(0, mc.MC_GPI, out value1);
                        var status1 = Convert.ToString(value, 2).PadLeft(16, '0');
                        if (status1[15] == '0')
                        {
                            await Control.GetDi(0, mc.MC_GPI, out value);
                            var aa = Convert.ToString(value, 2).PadLeft(16, '0');
                            if (aa[12] == '1')
                            {
                                await ToastService.Warning("提示", "当前为手动模式");
                            }
                            else
                            {
                                if (GlobalStatus.IsXZeroBack && GlobalStatus.IsYZeroBack && GlobalStatus.IsZZeroBack)
                                {
                                    if (GlobalStatus.IsPause)
                                    {
                                        PauseRestEvent.Set();
                                        PauseSource = new();
                                        GlobalStatus.IsPause = false;
                                        mc.GT_CrdStart(0, 1, 0);
                                        await Control.SetDoBit(0, mc.MC_GPO, 4, 0);
                                        await Control.SetDoBit(0, mc.MC_GPO, 3, 1);
                                        var isComplete = await CheckStatus(true);
                                        if (isComplete && !GlobalStatus.IsPause)
                                        {
                                            await InvokeAsync(async () =>
                                            {
                                                await CrdStop();
                                                StateHasChanged();
                                            });
                                            GlobalStatus.IsMarked = false;
                                            await Control.SetDoBit(0, MC_GPO, 11, 0);
                                            PauseSource.Cancel();
                                        }
                                    }
                                    else if (GlobalStatus.IsStop)
                                    {
                                        FinishToken = new();
                                        GlobalStatus.IsStop = false;
                                        var trap = new mc.TTrapPrm();
                                        trap.acc = 0.1;
                                        trap.dec = 0.1;
                                        trap.smoothTime = 49;
                                        await Control.SetPTP(0, (short)MarkOption.AxisCode.X, 100, 0, ref trap);
                                        await Control.SetPTP(0, (short)MarkOption.AxisCode.Y, 100, 0, ref trap);
                                        await Control.SetPTP(0, (short)MarkOption.AxisCode.Z, 15, 0, ref trap);
                                        int statusx;
                                        do
                                        {
                                            await Task.Delay(100);
                                            mc.GT_GetSts(0, (short)MarkOption.AxisCode.X, out statusx, 1, out _);
                                        } while ((statusx & 0x400) != 0);
                                        int status2;
                                        do
                                        {
                                            await Task.Delay(100);
                                            mc.GT_GetSts(0, (short)MarkOption.AxisCode.Y, out status2, 1, out _);
                                        } while ((status2 & 0x400) != 0);
                                        int status3;
                                        do
                                        {
                                            await Task.Delay(100);
                                            mc.GT_GetSts(0, (short)MarkOption.AxisCode.X, out status3, 1, out _);
                                        } while ((status3 & 0x400) != 0);

                                        await Mark();
                                    }
                                    else
                                    {
                                        await Mark();
                                    }
                                }
                                else
                                {
                                    await ToastService.Warning("提示", "请先进行机械回零");
                                }
                            }
                        }
                    }
                }
                catch (Exception)
                {
                }
            }
        }

        private async Task OnClick(Original original)
        {
            if (GlobalStatus.IsMarked)
            {
                await ToastService.Error("提示", "正在打码中，请勿切换版面信息");
            }
            else
            {
                CurrentOriginalIndex = Info.Originals.IndexOf(original) + 1;
                CurrentOriginal = original;
                Content = SvgBuilderExtension.Create(CurrentOriginal);
                await SvgEditor.UpdateAsync(Content);
                StateHasChanged();
            }
        }

        private async Task Stop()
        {

            await Control.Stop(0, 1 << (2 - 1), 0);
            await Control.Stop(0, 1 << (3 - 1), 0);
            await Control.Stop(0, 1 << (4 - 1), 0);
            await Control.Stop(0, 1 << 8, 1 << 8);
            mc.GT_CrdClear(0, 1, 0);
            mc.GT_CrdClear(0, 1, 1);
            GlobalStatus.IsMarked = false;
            FinishToken.Cancel();
            PauseSource.Cancel();
            Count = 0;
            if (!GlobalStatus.IsStop)
            {
                GlobalStatus.IsStop = true;
            }

            if (Items[CurrentOriginalIndex - 1] != null)
            {
                Items[CurrentOriginalIndex - 1].Status = Status.NoPrint;
                await InvokeAsync(async () =>
                {
                    await Table.QueryAsync();
                });
            }
        }

        private async Task<bool> CheckStatus(bool isPause = false)
        {
            // 指令返回值变量
            short sRtn;
            // 坐标系运动状态查询变量
            short run = 10;
            // 坐标系运动完成段查询变量
            int segment;
            int pre = 0;
            GT_CrdStatus(0, 1, out run, out segment, 0);
            while (run == 1 && !PauseSource.IsCancellationRequested && !GlobalStatus.IsEmergencyStop)
            {
                // 查询坐标系1的FIFO的插补运动状态
                sRtn = GT_CrdStatus(0, 1, out run, out segment, 0);
                // 坐标系在运动, 查询到的run的值为1
                if (segment != 0 && PauseSegment != segment && segment <= CurrentOriginal.MarkPoints.Count)
                {
                    PauseSegment = 0;
                    if (segment > pre)
                    {

                        if (MarkRestEvent.WaitOne() && PauseRestEvent.WaitOne())
                        {
                            mc.GT_Stop(0, 1 << 8, 0);
                            mc.GT_GetPrfPos(0, 2, out double posx, 1, out _);
                            mc.GT_GetPrfPos(0, 3, out double posy, 1, out _);
                            MarkRestEvent.Reset();
                            if (PauseSource.IsCancellationRequested)
                            {
                                MarkRestEvent.Set();
                            }
                        }
                    }
                }
            }

            if (PauseSource.IsCancellationRequested)
            {
                MarkRestEvent.Set();
                return false;
            }
            else
            {
                if (GlobalStatus.IsPause)
                {
                    return false;
                }
                else if (GlobalStatus.IsStop)
                {
                    return false;
                }
                else
                {
                    Count = 0;
                    FirstMark = false;
                    return true;
                }
            }
        }

        private async Task<bool> OnMarkFinish()
        {
            await Print.JumpTo(0, 0, 0, 1000);
            var layerCount = 0;
            var mEntities = new E3_ID[layerCount];
            var temp = await CodeTemplateService.GetByOrderNo(CurrentOriginal.MarkPoints[Count].Info.ToString());
            await Print.LoadTemplateAsync(temp.TemplatePath!, out layerCount, out mEntities);

            var id = await Print.Copy();
            await Print.MirrorEnt(id, 0, 0, MarkOption.MarkArgs.IsMirrorX, MarkOption.MarkArgs.IsMirrorY);
            var offset = MarkOption.MarkArgs.MarkAngleOffset / (180 / Math.PI);
            if (!CurrentOriginal.MarkPoints[Count].IsRotate)
            {
                await Print.MarkerSetRotateMoveParam(0 + offset);
            }
            else
            {
                await Print.MarkerSetRotateMoveParam(1.570797 + offset);
            }
            if (temp.Type == DataAccess.Models.MarkType.QRcode)
            {
                foreach (var item in mEntities)
                {
                    var name = new StringBuilder();
                    EzdKernel.E3_GetEntityName(item, name);
                    var entityName = name?.ToString();
                    if (!string.IsNullOrEmpty(entityName))
                    {
                        if (entityName == "1")
                        {
                            var tempArr = temp.MatchingNo!.Split(",");
                            var str = "";
                            foreach (var match in tempArr)
                            {
                                if (match == "0")
                                {
                                    str += CurrentOriginal.MarkPoints[Count].Customer + ",";
                                }

                                if (match == "1")
                                {
                                    str += CurrentOriginal.MarkPoints[Count].OrderNo + ",";
                                }

                                if (match == "2")
                                {
                                    str += CurrentOriginal.MarkPoints[Count].ProductID + ",";
                                }

                                if (match == "3")
                                {
                                    str += CurrentOriginal.MarkPoints[Count].SheetWidth + ",";
                                }

                                if (match == "4")
                                {
                                    str += CurrentOriginal.MarkPoints[Count].SheetHeight + ",";
                                }

                                if (match == "5")
                                {
                                    str += CurrentOriginal.MarkPoints[Count].FloorNo + ",";
                                }

                                if (match == "6")
                                {
                                    str += CurrentOriginal.MarkPoints[Count].HJ + ",";
                                }
                            }

                            await Print.ChangeTextByName(id, "1", CurrentOriginal.MarkPoints[Count].Customer!);
                        }

                        if (entityName == "2")
                        {
                            await Print.ChangeTextByName(id, entityName, CurrentOriginal.MarkPoints[Count].HJ!.ToString());
                        }
                    }
                }
            }
            await Task.Delay(100);
            var ret = await Print.MarkerMarkEnt2Async(id);
            if (ret == 0)
            {
                await Print.JumpTo(0, 0, 0, 1000);
                mc.GT_GetPrfPos(0, 2, out double posx, 1, out _);
                mc.GT_GetPrfPos(0, 3, out double posy, 1, out _);
                await EventBus.Log(new DataAccess.Models.AuditLog() { Description = $"当前打标位置: {(posx * MarkOption.XPluse.Value).ToString("0")} MM,{(posy * MarkOption.YPluse.Value).ToString("0")} MM,标签名称：{temp.TemplateName}" });
            }
            return ret == 0;
        }

        public void Dispose()
        {
            if (Timer != null)
            {
                Timer.Dispose();
            }
            GC.SuppressFinalize(this);
        }
    }
}
